#include "cybertron/network/SocketTcpClientSync.hpp"
#include "AsioSocketSync.hpp"

CYBERTRON_BEGIN

CybertronCoreAPI SocketTcpClientSync::SocketTcpClientSync(
int32_t recvTimeoutMS,
int32_t sendTimeoutMS) :
mRecvTimeoutMS(recvTimeoutMS),
mSendTimeoutMS(sendTimeoutMS)
{
	zeroMembers();
}

CybertronCoreAPI SocketTcpClientSync::~SocketTcpClientSync()
{
	closeThis();
}

void SocketTcpClientSync::zeroMembers()
{
	mRemotePort = 0;
}

void SocketTcpClientSync::closeThis()
{
	if (mImpl != nullptr)
	{
		mImpl->close();
		mImpl = nullptr;
	}

	mpContext = nullptr;

	mRemoteIp.clear();

	zeroMembers();
}

CybertronCoreAPI bool SocketTcpClientSync::connect(const std::string& ip, int port)
{
	close();

	std::shared_ptr<asio::io_context> pContext = std::make_shared<asio::io_context>();

	mpContext = pContext;
	mImpl = std::make_shared<AsioSocketSync>(pContext, mRecvTimeoutMS, mSendTimeoutMS);

	asio::ip::tcp::resolver resolver(*pContext);
	auto endpoints = resolver.resolve({ ip.c_str(), std::to_string(port).c_str() });

	mRemoteIp = ip;
	mRemotePort = port;

	return mImpl->connect(endpoints, nullptr);
}

CybertronCoreAPI bool SocketTcpClientSync::send(const Message& msg)
{
	if (mImpl != nullptr)
	{
		return mImpl->send(msg);
	}

	return false;
}


CybertronCoreAPI bool SocketTcpClientSync::send(const std::string& msg)
{
    if (mImpl != nullptr)
    {
        return mImpl->send(msg);
    }

    return false;
}

CybertronCoreAPI bool SocketTcpClientSync::send(
	std::uint16_t msgId,
	const google::protobuf::MessageLite& protobufMsg)
{
	Message msg;
	msg.fromProtobuf(msgId, protobufMsg);

	if (mImpl != nullptr)
	{
		return mImpl->send(msg);
	}

	return false;
}

CybertronCoreAPI void SocketTcpClientSync::sendHeartbeat()
{
	if (mImpl != nullptr)
	{
		mImpl->sendHeartbeat();
	}
}

CybertronCoreAPI bool SocketTcpClientSync::receive(Message& msg, int32_t recvTimeoutMS)
{
	mRecvTimeoutMS = recvTimeoutMS;
	if (mImpl != nullptr)
	{
		return mImpl->receiveMessage(msg, recvTimeoutMS);
	}

	return false;
}

CybertronCoreAPI bool SocketTcpClientSync::receive(Message& msg)
{
	if (mImpl != nullptr)
	{
		return mImpl->receiveMessage(msg);
	}

	return false;
}

CybertronCoreAPI int SocketTcpClientSync::receiveEnhance(Message& msg, int32_t recvTimeoutMS)
{
	mRecvTimeoutMS = recvTimeoutMS;
	if (mImpl != nullptr)
	{
		return mImpl->receiveMessageEnhance(msg, recvTimeoutMS);
	}
	return -1;
}
CybertronCoreAPI int SocketTcpClientSync::receiveEnhanceEx(Message& msg, int32_t recvTimeoutMS)
{
	mRecvTimeoutMS = recvTimeoutMS;
	if (mImpl != nullptr)
	{
		return mImpl->receiveMessageEnhanceEx(msg, recvTimeoutMS);
	}
	return -1;
}
CybertronCoreAPI int SocketTcpClientSync::receiveEnhance(Message& msg)
{
	if (mImpl != nullptr)
	{
		return mImpl->receiveMessageEnhance(msg);
	}
	return -1;
}


CybertronCoreAPI bool SocketTcpClientSync::receive(std::string& msg)
{
    if (mImpl != nullptr)
    {
        return mImpl->receiveMessage(msg);
    }

    return false;
}

CybertronCoreAPI void SocketTcpClientSync::close()
{
	closeThis();
}

CybertronCoreAPI const std::string& SocketTcpClientSync::getRemoteIp() const
{
	return mRemoteIp;
}

CybertronCoreAPI int SocketTcpClientSync::getRemotePort() const
{
	return mRemotePort;
}

CybertronCoreAPI ESocketStatus SocketTcpClientSync::getStatus() const
{
	if (mImpl != nullptr)
	{
		return mImpl->getStatus();
	}

	return ESocketStatus_Closed;
}

CYBERTRON_END
